﻿#include "ui_msg_handle.h"

#include "ui_msg/request_generated.h"
#include "ui_msg/response_generated.h"
#include "ui_msg/wubi_def_generated.h"

#include "../scheme/wubi_scheme.h"
#include "../../log_tool.h"
#include <windows.h>

#include "ui_msg/ui_msg_def.h"

using namespace WubiUIMsg;

// 只能用那么多buffer。
class MsgAllocator : public flatbuffers::Allocator
{
public:
    uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE
    {
        static uint8_t *s_buffer = new uint8_t[UI_PIPE_SIZE];
        assert(size <= UI_PIPE_SIZE);
        return s_buffer;
    }

    void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE
    {
        // 不处理
        p;
    }
};



bool UIMsgHandler::handleMsg(HANDLE hPipe,
                             std::shared_ptr<WubiSchemeMgr> &schemeMgr,
                             char *data, int data_len)
{

    static MsgAllocator allocator;

    auto request = GetUIRequest(data);
    flatbuffers::FlatBufferBuilder fbb(UI_PIPE_SIZE, &allocator);
    bool result = false;


    auto cmd = request->cmd();
    LOG_DEBUG("receive cmd %d", cmd);
    switch (cmd)
    {
    case WubiCmd_GetAllSchemes:
    {
        std::vector<WubiBaseInfoPtr> schemes;
        result = schemeMgr->getSchemes(schemes);

        std::vector<flatbuffers::Offset<UIRspSchemeInfo>> scheme_vec;
        for (auto &scheme : schemes)
        {
            auto name = fbb.CreateString(scheme->name);
            auto scheme_info = CreateUIRspSchemeInfo(fbb,
                                                     scheme->id,
                                                     name,
                                                     static_cast<uint16_t>(scheme->candidate_count));
            scheme_vec.push_back(scheme_info);
        }
        auto schemes_vec = fbb.CreateVector(scheme_vec);
        auto rsp = CreateUIRspSchemeList(fbb, schemes_vec);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspSchemeList,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_getCodeTables: // 新增处理获取码表列表的case
    {
        auto params = request->params_as<UIReqGetCodeTables>();
        std::vector<WubiBaseInfoPtr> tables;
        result = schemeMgr->getCodeTables(params->scheme_id(), tables);

        std::vector<flatbuffers::Offset<UIRspTableInfo>> table_vec;
        for (auto &table : tables)
        {
            auto name = fbb.CreateString(table->name);
            auto table_info = CreateUIRspTableInfo(fbb,
                                                  table->id,
                                                  name,
                                                  table->codetable_enable);
            table_vec.push_back(table_info);
        }
        auto tables_vec = fbb.CreateVector(table_vec);
        auto rsp = CreateUIRspCodeTableList(fbb, tables_vec);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspCodeTableList,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_CreateScheme:
    {
        auto params = request->params_as<UIReqCreateScheme>();
        auto new_id = schemeMgr->createScheme(params->name()->c_str());
        result = (new_id != 0);

        auto rsp = CreateUIRspCreateScheme(fbb, new_id);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspCreateScheme,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_DeleteScheme:
    {
        auto params = request->params_as<UIReqDeleteScheme>();
        result = schemeMgr->deleteScheme(params->id());

        auto rsp = CreateUIRspDeleteScheme(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspDeleteScheme,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_UpdateScheme:
    {
        auto params = request->params_as<UIReqUpdateScheme>();
        result = schemeMgr->updateScheme(
            params->id(),
            params->name()->str(),
            params->candidate_count());

        auto rsp = CreateUIRspUpdateScheme(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspUpdateScheme,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_AddCodeTable:
    {
        auto params = request->params_as<UIReqAddCodeTable>();
        auto new_id = schemeMgr->addCodeTable(
            params->scheme_id(),
            params->name()->str(),
            params->file_path()->str());
        result = (new_id != 0);

        auto rsp = CreateUIRspAddCodeTable(fbb, new_id);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspAddCodeTable,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_GetCandidateList:
    {
        auto params = request->params_as<UIReqGetCandidateList>();
        std::vector<std::string> candidates;
        result = schemeMgr->getCandidateList(params->code()->str(), candidates);

        std::vector<flatbuffers::Offset<flatbuffers::String>> candidate_vec;
        for (auto &cand : candidates)
        {
            candidate_vec.push_back(fbb.CreateString(cand));
        }
        auto candidates_vec = fbb.CreateVector(candidate_vec);
        auto rsp = CreateUIRspCandidateList(fbb, candidates_vec);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspCandidateList,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_SetCurrentSchemeId:
    {
        auto params = request->params_as<UIReqSetCurrentSchemeId>();
        result = schemeMgr->setCurrentSchemeId(params->id());

        auto rsp = CreateUIRspSetCurrentSchemeId(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspSetCurrentSchemeId,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_RemoveCodeTable:
    {
        auto params = request->params_as<UIReqRemoveCodeTable>();
        result = schemeMgr->removeCodeTable(
            params->scheme_id(),
            params->code_table_id());

        auto rsp = CreateUIRspRemoveCodeTable(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspRemoveCodeTable,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_ReloadWordDic:
    {
        result = schemeMgr->reloadWordDic();

        auto rsp = CreateUIRspReloadWordDic(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspReloadWordDic,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_GetCurrentSchemeId:
    {
        auto id = schemeMgr->getCurrentSchemeId();
        result = (id != 0);

        auto rsp = CreateUIRspGetCurrentSchemeId(fbb, id);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspGetCurrentSchemeId,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_SwapCodeTableOrder:
    {
        auto params = request->params_as<UIReqSwapCodeTableOrder>();
        result = schemeMgr->swapCodeTableOrder(params->id1(), params->id2());

        auto rsp = CreateUIRspSwapCodeTableOrder(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspSwapCodeTableOrder,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_GetCodeTableDataByCode:
    {
        auto params = request->params_as<UIReqGetCodeTableDataByCode>();
        std::vector<WubiCodetableData> words;
        result = schemeMgr->getCodeTableDataByCode(params->id(), params->code()->str(), words);

        std::vector<flatbuffers::Offset<UIRspWubiCodetableData>> word_vec;
        for (auto &word : words) {
            auto word_str = fbb.CreateString(word.word);
            auto word_data = CreateUIRspWubiCodetableData(fbb, word.id, word_str);
            word_vec.push_back(word_data);
        }
        auto words_vec = fbb.CreateVector(word_vec);
        auto rsp = CreateUIRspGetCodeTableDataByCode(fbb, words_vec);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspGetCodeTableDataByCode,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_SwapCodeTableDataOrder:
    {
        auto params = request->params_as<UIReqSwapCodeTableDataOrder>();
        result = schemeMgr->swapCodeTableDataOrder(
            params->code_table_id(),
            params->code_id1(),
            params->code_id2());

        auto rsp = CreateUIRspSwapCodeTableDataOrder(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspSwapCodeTableDataOrder,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_AddWord:
    {
        auto params = request->params_as<UIReqAddWord>();
        auto new_code_id = schemeMgr->addWord(
            params->code_table_id(),
            params->code()->str(),
            params->word()->str());
        result = (new_code_id != 0);

        auto rsp = CreateUIRspAddWord(fbb, new_code_id);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspAddWord,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_RemoveWord:
    {
        auto params = request->params_as<UIReqRemoveWord>();
        result = schemeMgr->removeWord(params->code_id());

        auto rsp = CreateUIRspRemoveWord(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspRemoveWord,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_SetCodeTableEnable:
    {
        auto params = request->params_as<UIReqSetCodeTableEnable>();
        result = schemeMgr->setCodeTableEnable(
            params->code_table_id(),
            params->enable());

        auto rsp = CreateUIRspSetCodeTableEnable(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       result,
                                       UIRspParam_UIRspSetCodeTableEnable,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_GetCodeByWord:  // 新增编码反查处理
    {
        auto params = request->params_as<UIReqGetCodeByWord>();
        std::vector<std::string> codes;
        result = schemeMgr->getCodeByWord(params->word()->str(), codes);

        std::vector<flatbuffers::Offset<flatbuffers::String>> code_vec;
        for (auto &code : codes) {
            code_vec.push_back(fbb.CreateString(code));
        }
        auto codes_vec = fbb.CreateVector(code_vec);
        auto rsp = CreateUIRspGetCodeByWord(fbb, codes_vec);
        auto ui_rsp = CreateUIResponse(fbb,
                                      request->cmd(),
                                      result,
                                      UIRspParam_UIRspGetCodeByWord,
                                      rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    case WubiCmd_ExportCodeTable:  // 新增导出码表处理
    {
        auto params = request->params_as<UIReqExportCodeTable>();
        result = schemeMgr->exportCodeTable(
            params->code_table_id(),
            params->file_path()->str());

        auto rsp = CreateUIRspExportCodeTable(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                      request->cmd(),
                                      result,
                                      UIRspParam_UIRspExportCodeTable,
                                      rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }
    default:
        auto rsp = CreateUIRspNoData(fbb);
        auto ui_rsp = CreateUIResponse(fbb,
                                       request->cmd(),
                                       false,
                                       UIRspParam_UIRspNoData,
                                       rsp.Union());
        fbb.Finish(ui_rsp);
        break;
    }

    DWORD bytesWritten;
    return WriteFile(hPipe,
                     fbb.GetBufferPointer(),
                     fbb.GetSize(),
                     &bytesWritten,
                     nullptr);
}